﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace BattleTank3D
{
    /// <summary>
    /// Classe Inimigo
    /// 
    /// Implementa o inimigo do jogo cujo comportamento é mover-se aleatóriamente pelo terreno até que aviste o jogador. Uma vez avistado
    /// o jogador o inimigo encaminha-se para sua última posição conhecida.
    /// 
    /// autor: Turma XNA Dev2709a
    /// </summary>
    class Inimigo
    {
   
        /// <summary>
        /// posição do inimigo no terreno
        /// </summary>
        public Vector3 position;
        
        /// <summary>
        /// alcance visual do inimigo
        /// </summary>
        int lineOfSight;
        
        /// <summary>
        /// vetor direção na qual o inimigo está se movendo
        /// </summary>
        public Vector3 direction;// { get; set; }


        /// <summary>
        /// velocidade de movimento do inimigo
        /// </summary>
        public float speed { get; set; }

        
        /// <summary>
        /// modelo do inimigo
        /// </summary>
        public Model model { get; set; }

        /// <summary>
        /// alvo do inimigo. Segundo seu comportamento, o inimigo caminha para um alvo randomico até que chegue a esta posição ou aviste o jogador.
        /// Caso aviste o jogador, a posição deste passa a ser o novo alvo. Caso chegue ao alvo sem avistar o jogador um novo alvo será determinado.
        /// </summary>
        public Vector3 target;

        

        /// <summary>
        /// Construtor da classe inimigo. Atribui alguns valores.
        /// </summary>
        public Inimigo()
        {
            this.position = Vector3.Zero;
            this.lineOfSight = 20;
            this.target = this.position;
            this.speed = 0.1f;            
        }

        /// <summary>
        /// Método que verifica se uma posição P está dentro do alcance visual do inimigo (círculo centrado na posição do inimigo com raio lineOfSight).
        /// </summary>
        /// <param name="p">posição a ser verificada</param>
        /// <returns>true caso esteja dentro do alcance e false caso contrario</returns>
        public bool isSeeing(Vector3 p)
        {
            //Checa se a posição P está dentro do alcance do círculo com centro na posição do inimigo
            if (((p.X - this.position.X) * (p.X - this.position.X) +
                 (p.Z - this.position.Z) * (p.Z - this.position.Z)) <= (this.lineOfSight * this.lineOfSight))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Desenha o modelo na tela
        /// </summary>
        /// <param name="view"></param>
        /// <param name="proj"></param>
        public void Draw(Matrix view, Matrix proj)
        {
            model.Draw(Matrix.CreateTranslation(this.position), view, proj);
        }

        /// <summary>
        /// Desenha o modelo no Mapa
        /// </summary>
        /// <param name="view"></param>
        /// <param name="proj"></param>
        public void DrawOnMap(Matrix view, Matrix proj)
        {
            model.Draw(Matrix.CreateTranslation(this.position), view, proj);
        }

        /// <summary>
        /// Move o inimigo em direção ao jogador. Caso o jogador não esteja dentro do alcance visual, atribui uma posição randômica
        /// como alvo e move-se em direção a ela. Se já atingiu essa posição, atribui uma nova posição randômica.
        /// </summary>
        /// <param name="p">posição do jogador</param>
        public void move(Vector3 p)
        {
            //se está vendo o jogador, este passa a ser o alvo
            if (isSeeing(p))
            {
                this.target = p;                    
            }
            // Se não está vendo o jogador
            else
            {
                //se já chegou ao alvo
                if ((this.position.X > this.target.X - 2) &&
                    (this.position.X < this.target.X + 2) &&
                    (this.position.Z > this.target.Z - 2) &&
                    (this.position.Z < this.target.Z + 2))
                {
                    //obtem novo alvo
                    Random random = new Random(DateTime.Now.Millisecond);
                    float x = random.Next(0, 1000);
                    float z = random.Next(0, 1000);
                    this.target = new Vector3(x, 0, z);
                }
            }
            this.direction = this.target - this.position;
            this.direction.Normalize();

            /*Vector3 temp = this.position;
            temp.Normalize();
            Matrix rotation = Matrix.CreateRotationY((float)Math.Acos(Vector3.Dot(Vector3.Zero, this.direction)));
            this.position = Vector3.Transform(temp, rotation);
            */
            this.direction.X *= this.speed;
            this.direction.Z *= this.speed;
            Matrix translation = Matrix.CreateTranslation(this.direction);
            this.position = Vector3.Transform(this.position, translation);
            
            
            
        }

        /// <summary>
        /// altera a posição do inimigo
        /// </summary>
        /// <param name="v">posição do inimigo</param>
        public void setPosition(Vector3 v)
        {
            this.position = v;
        }

        public Vector3 getPosition()
        {
            return this.position;
        }

        /// <summary>
        /// atualiza o inimigo
        /// </summary>
        /// <param name="p">posição do inimigo</param>
        public void Update(Vector3 p)
        {
            //move-se buscando o jogador
            this.move(p);
        }
    }
}

